package sfs

import (
	"context"
	"github.com/chicken-team-outside/chicken_transmission/api_messages"
	"github.com/chicken-team-outside/chicken_transmission/driver"
	"github.com/golang/protobuf/proto"
	"go.uber.org/zap"
	"os"
)

func (p *FsClient) CalculateFileBlocksSha1(ctx context.Context, clientId uint64, path string, blockSize int32) (*api_messages.CalculateFileBlocksSha1Reply, error) {
	timeout := p.timeout.Load()
	handler := NewOperatorKeeperClient(ctx, p, timeout)
	defer handler.Close()
	result, err := handler.QueryAndWait(clientId, api_messages.MessageType_CalculateFileBlocksSha1, &api_messages.CalculateFileBlocksSha1Query{
		Path:      path,
		BlockSize: blockSize,
		Timeout:   int32(timeout),
	})
	if err != nil {
		return nil, err
	}
	reply := new(api_messages.CalculateFileBlocksSha1Reply)
	err = proto.Unmarshal(result, reply)
	if err != nil {
		return nil, err
	}
	return reply, nil
}

func (p *FsClient) calculateFileBlocksSha1Provider(ctx context.Context, header *api_messages.MessageHeader, data []byte) {
	if ctx.Err() == nil {
		query := new(api_messages.CalculateFileBlocksSha1Query)
		err := proto.Unmarshal(data, query)
		if err != nil {
			zap.L().Warn("failed to unmarshal query", zap.Error(err))
			return
		}
		keeper := NewOperatorKeeperServer(context.Background(), header.ClientId, header.Id, p, query.Timeout)
		defer keeper.Close()
		go keeper.keepAlive()
		var localDriver driver.LocalDriver
		if err == nil {
			localDriver = p.GetLocal()
			if localDriver == nil {
				err = ErrNotSetLocalDriver
			}
		}
		var stat os.FileInfo
		if err == nil {
			stat, err = localDriver.Stat(query.Path)
		}
		reply := new(api_messages.CalculateFileBlocksSha1Reply)
		var file driver.LocalDriverFile
		if err == nil {
			reply.Size = stat.Size()
			file, err = localDriver.OpenFile(query.Path, os.O_RDONLY, os.ModePerm)
		}
		if err == nil {
			defer file.Close()
			reply.Sha1List, err = CalculateFileBlocksSha1(file, reply.Size, query.BlockSize)
		}
		if err != nil {
			err = keeper.sendError(err)
		} else {
			err = keeper.success(reply)
		}
		if err != nil {
			zap.L().Warn("failed to send replay", zap.Error(err))
		}
	}
}
